# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2023/4/21 22:00
# @Author : xyjiang1216
# @Email : jiangxuyan@nudt.edu.cn
# @File : op_struct_init_module.py
# @Version: OpenPlanner2.0
import json
from typing import List, Dict

from OpenPlanner.core.api.algo_input_class import AlgoInput
from OpenPlanner.core.api.algo_output_class import AlgoOutput
from OpenPlanner.debug.debug_utils import DEBUG_PRINT


class TopoParam:
    def __init__(self,
                 sw_num: int,
                 es_num_per_sw_set: List[int],
                 speed_set_per_link: List[int],
                 st_queue_set_per_link: List[int],
                 port_flag: str,
                 user_defined_param: Dict
                 ):
        self.sw_num: int = sw_num
        self.es_num_per_sw_set: List[int] = \
            es_num_per_sw_set
        self.speed_set_per_link: List[int] = \
            speed_set_per_link
        self.st_queue_set_per_link: List[int] = \
            st_queue_set_per_link
        self.port_flag: str = port_flag
        self.user_defined_param: Dict = user_defined_param


class StreamParam:
    def __init__(self,
                 stream_num: int,
                 size_set: List[int],
                 period_set: List[int],
                 # latency_requirement_set: List[int],
                 # jitter_requirement_set: List[int]
                 user_defined_param: Dict
                 ):
        self.stream_num = stream_num
        self.size_set = size_set
        self.period_set = period_set
        # self.latency_requirement_set = \
        #     latency_requirement_set
        # self.jitter_requirement_set = \
        #     jitter_requirement_set
        self.user_defined_param = user_defined_param


class ScenarioVerifyOption:
    def __init__(self,
                 topo_verification: int,
                 stream_verification: int):
        self.topo_verification = topo_verification
        self.stream_verification = stream_verification


class AlgoParam:
    def __init__(self,
                 base_module: str,
                 algo_func: str):
        if base_module == '':
            print("Error: algo_param的base_module"
                  "不能为空，"
                  "请更新配置文件")
            exit(0)
        if algo_func == '':
            print("Error: algo_param的algo_func"
                  "不能为空，"
                  "请更新配置文件")
            exit(0)
        self.base_module = base_module
        self.algo_func = algo_func


class HookParam:
    def __init__(self,
                 base_module_path: str,
                 hook_func_name: str,
                 hook_func_param: Dict):
        self.base_module_path: str = base_module_path
        self.hook_func_name: str = hook_func_name
        self.hook_func_param: Dict = hook_func_param


class EvalParam:
    def __init__(self,
                 latency_eval_flag,
                 jitter_eval_flag,
                 porosity_eval_flag):
        self.latency_eval_flag = latency_eval_flag
        self.jitter_eval_flag = jitter_eval_flag
        self.porosity_eval_flag = porosity_eval_flag


class InitInput:
    def __init__(self,
                 base_module_path: str,
                 user_defined_link: str,
                 user_defined_stream: str,
                 user_defined_instance: str):
        self.base_module_path = base_module_path
        self.user_defined_link = user_defined_link
        self.user_defined_stream = user_defined_stream
        self.user_defined_instance = user_defined_instance


class OPClass:
    def __init__(self,
                 conf_filepath: str):
        self.conf_filepath = conf_filepath

        # 文件
        self.topo_filepath: str = ''
        self.stream_filepath: str = ''
        self.solution_filepath: str = ''
        # 算法参数
        self.algo_input: AlgoInput = AlgoInput()
        self.algo_output: AlgoOutput = AlgoOutput()
        # 粘合参数
        self.topo_type: int = None
        self.topo_param: TopoParam = None
        self.stream_instance_flag: str = ''
        self.stream_param: StreamParam = None
        self.scenario_verify_option: ScenarioVerifyOption = None
        self.init_input: InitInput = None
        self.algo_strategy: str = ''
        # self.algo_param: AlgoParam = None
        self.algo_base_module: str = ''
        self.algo_param: Dict = {}
        self.solution_transformation_option: str = ''
        self.solution_verification_option: str = ''
        self.solution_evaluation_option: EvalParam = ''
        # 钩子参数
        self.topo_hook: HookParam = None
        self.stream_hook: HookParam = None
        self.input_init_hook: HookParam = None
        self.output_transform_hook: HookParam = None
        self.quality_eval_hook: HookParam = None

        self._init_conf_param()

    def _init_conf_param(self):
        conf = self.conf_filepath
        with open(conf) as fd:
            data = json.load(fd)

        # DEBUG_PRINT(data)
        '''拓扑构建层'''
        topo_construction = data['topo_construction']
        self.topo_type = topo_construction['type']
        if topo_construction['topo_filepath'] == '':
            print('Error: 配置文件中topo_filepath不能为空！')
            exit(0)
        bool_topo_filepath = \
            topo_construction['topo_filepath'].endswith(".json")
        if not bool_topo_filepath:
            print('Warning: 推荐使用json作为流量文件的格式，'
                  '请使用.json作为topo_filepath的后缀！')
            exit(0)
        self.topo_filepath = topo_construction['topo_filepath']
        self.topo_param = \
            TopoParam(**topo_construction['topo_param'])
        self.topo_hook = \
            HookParam(**topo_construction['topo_hook'])

        '''流量构建层'''
        stream_construction = data['stream_construction']
        if stream_construction['stream_filepath'] == '':
            print('Error: 配置文件中stream_filepath不能为空！')
            exit(0)
        bool_stream_filepath = \
            stream_construction['stream_filepath'].endswith(".json")
        if not bool_stream_filepath:
            print('Warning: 推荐使用json作为流量文件的格式，'
                  '请使用.json作为stream_filepath的后缀！')
            exit(0)
        self.stream_filepath = \
            stream_construction['stream_filepath']
        self.stream_instance_flag = \
            stream_construction['stream_instance_flag']
        self.stream_param = \
            StreamParam(
                **stream_construction['stream_param']
            )
        self.stream_hook = \
            HookParam(
                **stream_construction['stream_hook']
            )

        '''场景验证层'''
        scenario_verification = data['scenario_verification']
        self.scenario_verify_option = ScenarioVerifyOption(**scenario_verification)

        '''输入预处理层'''
        input_initialization = data['input_initialization']
        self.init_input = InitInput(
            **input_initialization['user_defined_param']
        )
        self.input_init_hook = HookParam(
            **input_initialization['input_init_hook']
        )

        '''规划算法层'''
        planning_algorithm = data['planning_algorithm']
        if planning_algorithm['algo_strategy'] == '':
            print('Error: 算法策略（algo_strategy）'
                  '不能为空，'
                  '请更新配置文件')
            exit(0)
        self.algo_strategy = \
            planning_algorithm['algo_strategy']
        if planning_algorithm['algo_base_module'] == '':
            print('Error: 算法模块不能为空，'
                  '请更新配置文件')
            exit(0)
        self.algo_base_module = \
            planning_algorithm['algo_base_module']
        if planning_algorithm['solution_filepath'] == '':
            print('Error: 配置文件中solution_filepath不能为空！')
            exit(0)
        bool_solution_filepath = \
            planning_algorithm['solution_filepath'].endswith(".json")
        if not bool_solution_filepath:
            print('Warning: 推荐使用json作为结果文件的格式，'
                  '请使用.json作为solution_filepath的后缀！')
            exit(0)
        self.solution_filepath = \
            planning_algorithm['solution_filepath']
        self.algo_param = \
            planning_algorithm['algo_param']

        '''输出转换层'''
        output_transformation = data['solution_transformation']
        self.solution_transformation_option = \
            output_transformation['solution_transform_option']
        self.output_transform_hook = HookParam(
            **output_transformation['transform_hook']
        )

        '''结果验证层'''
        solution_verification = data['solution_verification']
        self.solution_verification_option = \
            solution_verification['solution_verification_option']

        '''质量评估层'''
        solution_quality_evaluation = data['solution_quality_evaluation']
        self.solution_evaluation_option = \
            EvalParam(solution_quality_evaluation['latency_eval_flag'],
                      solution_quality_evaluation['jitter_eval_flag'],
                      solution_quality_evaluation['porosity_eval_flag'])
        self.quality_eval_hook = HookParam(
            **solution_quality_evaluation['quality_eval_hook']
        )

